#!/usr/bin/env python
# coding=utf8
# Last Change: 2010-03-16 23:08:13

from database import *
from gtalk import TimeZone
import gtalk

from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import xmpp
from google.appengine.api import users

from datetime import datetime, timedelta, tzinfo
from cgi import escape as e
import math
import random
import logging
import sys
import urllib

class Page(webapp.RequestHandler):

  def write(self, content):
    self.response.out.write(content.strip('\n'))

  def auth(self):
    user = users.get_current_user()
    user_email = user.email().lower()
    q = db.GqlQuery('SELECT * FROM Account WHERE gtalk = :1', user_email)
    if (q.count(1) == 1):
      return True
    else:
      logging.warning('{unauth web user} {%s} {%s}' % (user.email(), user.nickname()))
      self.error(403)
      self.write_header('403 Forbidden')
      self.write('<h1>403 Forbidden</h1>')
      self.write('<a href="%s">Logout, try again</a>' % (users.create_logout_url('/')))
      self.write_footer()
      return False

  def write_header(self, title):
    self.write('''
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head profile="http://gmpg.org/xfn/11">
<link rel="stylesheet" href="/styles/style.css" />
<title>
''')
    self.write(title + ' - Gtalk Group')
    self.write('''
</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
''')

  def write_footer(self):
    self.write('''
</body>
</html>
''')

  def write_table_header(self, headers, width=None):
    self.write('<table><thead>')
    for i, th in enumerate(headers):
      th = headers[i]
      if width and len(width) > i:
        self.write('<th style="width: %d%%">' % width[i])
      else:
        self.write('<th>')
      self.write(th)
      self.write('</th>')
    self.write('</thead>')
    self.write('<tbody>')

  def write_table_row(self, elems, tr_css_class=None, td_css_class=None):
    if tr_css_class != None:
      self.write('<tr class="%s">' % tr_css_class)
    else:
      self.write('<tr>')
    for i, td in enumerate(elems):
      if td_css_class and i < len(td_css_class) and td_css_class[i]:
        self.write('<td class="%s">' % td_css_class[i])
      else:
        self.write('<td>')
      self.write(td)
      self.write('</td>')
    self.write('</tr>')

  def write_table_footer(self):
    self.write('</tbody></table>')

class IndexPage(Page):

  def get(self):
    if not self.auth():
      return
    path = self.request.path
    param = urllib.unquote(path[1:])
    if len(param) == 0:
      offset = datetime.now()
    else:
      offset = datetime.fromtimestamp(float(param))
    self.write_header('Index')
    self.write('<h3>User Status</h3>')
    self.write('<p align="right"><a href="%s">logout</a></p>' % (users.create_logout_url('/')))
    self.write('<div id="status_table">')
    self.write_table_header(['user', 'gtalk', 'status'])
    for a in Account.all():
      is_online = xmpp.get_presence(a.gtalk)
      status = 'online' if is_online else 'offline'
      self.write_table_row([a.name, a.gtalk, status], td_css_class=[a.name, None, status])
    self.write_table_footer()
    self.write('</div>')
    #
    self.write('<hr />')
    self.write('<h3>Messages Graph</h3>')
    self.write('<div id="messages-graph">')
    messages_graph_offset = offset
    messages_graph_count = 0
    flag = True
    tag_dict = dict()
    while flag:
      q = db.GqlQuery('SELECT * FROM Message WHERE time < :1 ORDER BY time DESC LIMIT 300', messages_graph_offset)
      for m in q:
        if m.tag in tag_dict:
          tag_dict[m.tag] += 1
        else:
          tag_dict[m.tag] = 1
        height = len(m.content)
        height = min(100, height)
        height = max(1, height)
        top = 100 - height
        content_top = 100 - top
        message_time = float(m.time.strftime('%s')) + ((m.time.microsecond+1) / 1000000.0)
        self.write('<div class="message" onclick="location.href=\'/%f\';">' % message_time)
        self.write('<div class="line %s" style="height:%dpx;margin-top:%dpx;"></div>' % (m.sender, height, top))
        self.write('<div class="line %s" style="height:1px;margin-top:%dpx;"></div>' % (m.sender, top))
        content = gtalk.format_raw_message('<span class="%s">%s</span>' % (m.sender,m.sender), m.to, m.tag, e(m.content), m.time)
        content = content.replace('\n', '<br />')
        self.write('<div class="content">%s</div>' % content)
        self.write('</div>')
        messages_graph_offset = min(messages_graph_offset, m.time)
        messages_graph_count += 1
        if messages_graph_count >= 480:
          flag = False
          break
      if q.count() == 0:
        flag = False
        break
    self.write('</div>')
    self.write('<br />')
    self.write('<div class="paging"><p><a href="/">Home</a>')
    self.write('</p></div>')
    #
    self.write('<hr />')
    self.write('<h3>Tag Cloud</h3>')
    #
    self.write('<div class="tag_cloud">')
    max_count = 0
    min_count = sys.maxint
    for tag, count in tag_dict.iteritems():
      max_count = max(max_count, count)
      min_count = min(min_count, count)
    if max_count == min_count:
      max_count += 1
      min_count -= 1
    max_size = 22
    min_size = 10
    for tag, count in tag_dict.iteritems():
      if not tag:
        tag_name = 'none'
      else:
        tag_name = tag
      level = (count - min_count) / float(max_count - min_count)
      size = int(round((max_size - min_size)*level + min_size))
      self.write('<span style="font-size: %dpx;"><a href="/tag/%s">%s</a></span>' % (size, tag_name, tag))
    self.write('</div>')
    self.write('<hr />')
    #
    self.write('<h3>Messages</h3>')
    self.write('<div id="tag_table">')
    self.write_table_header(['From', 'To', 'Tag', 'Time', 'Content'], [5,15,5,12,63])
    q = db.GqlQuery('SELECT * FROM Message WHERE time < :1 ORDER BY time DESC LIMIT 30', offset)
    local_tz = TimeZone(8, 'GMT+8')
    utc_tz = TimeZone(0, 'GMT+0')
    next_offset = None
    for m in q:
      if len(m.to) != 0:
        to_str = reduce(lambda x, y: x + ', ' + y, map(lambda x: '@' + x, m.to))
      else:
        to_str = ''
      time_str = m.time.replace(tzinfo = utc_tz).astimezone(local_tz).strftime('%H:%M:%S, %b %d\n')
      if not next_offset:
        next_offset = m.time
      else:
        next_offset = min(m.time, next_offset)
      tag_str = m.tag if m.tag else ''
      self.write_table_row([m.sender, to_str, tag_str, time_str, e(m.content).replace('\n', '<br />')], m.sender)
    self.write_table_footer()
    self.write('</div>')
    if next_offset:
      tmp = next_offset
      next_offset = float(tmp.strftime('%s')) + (tmp.microsecond / 1000000.0)
      q = db.GqlQuery('SELECT * FROM Message WHERE time < :1 ORDER BY time DESC LIMIT 30', datetime.fromtimestamp(next_offset))
      self.write('<div class="paging"><p><a href="/">Home</a>')
      if q.count() != 0:
        self.write('<a href="/%f">Earlier</a>' % next_offset)
      self.write('</p></div>')
    self.write_footer()

class TagPage(Page):

  def get(self):
    if not self.auth():
      return
    path = self.request.path
    params = urllib.unquote(path[5:])
    params = params.split('/')
    if len(params) == 1:
      tag_str = params[0]
      offset = datetime.now()
    else:
      tag_str = params[0]
      offset = datetime.fromtimestamp(float(params[1]))
    if tag_str == 'none':
      tag = None
      self.write_header('No Tag')
    else:
      tag = tag_str
      self.write_header('Tag #%s' % tag)
    self.write('<div id="tag_table">')
    self.write_table_header(['From', 'To', 'Time', 'Content'], [5,15,12,68])
    q = db.GqlQuery('SELECT * FROM Message WHERE tag = :1 AND time < :2 ORDER BY time DESC LIMIT 30', tag, offset)
    local_tz = TimeZone(8, 'GMT+8')
    utc_tz = TimeZone(0, 'GMT+0')
    next_offset = None
    for m in q:
      if len(m.to) != 0:
        to_str = reduce(lambda x, y: x + ', ' + y, map(lambda x: '@' + x, m.to))
      else:
        to_str = ''
      time_str = m.time.replace(tzinfo = utc_tz).astimezone(local_tz).strftime('%H:%M:%S, %b %d\n')
      if not next_offset:
        next_offset = m.time
      else:
        next_offset = min(m.time, next_offset)
      self.write_table_row([m.sender, to_str, time_str, e(m.content).replace('\n', '<br />')], m.sender)
    self.write_table_footer()
    self.write('</div>')
    if next_offset:
      tmp = next_offset
      next_offset = float(tmp.strftime('%s')) + (tmp.microsecond / 1000000.0)
      q = db.GqlQuery('SELECT * FROM Message WHERE tag = :1 AND time < :2 ORDER BY time DESC LIMIT 30', tag, datetime.fromtimestamp(next_offset))
      self.write('<div class="paging"><p><a href="/">Home</a>')
      if q.count() != 0:
        self.write('<a href="/tag/%s/%f">Earlier</a>' % (tag_str, next_offset ))
      self.write('</p></div>')
    self.write_footer()

application = webapp.WSGIApplication([
  ('/tag/.+', TagPage),
  ('/.*', IndexPage)
  ], debug=True)

def main():
  run_wsgi_app(application)

if __name__ == '__main__':
  main()
